package com.guomei.service.impl;

import com.guomei.bean.SendVerifyCode;
import com.guomei.configs.SmsConfig;
import com.guomei.constans.RedisConstants;
import com.guomei.constans.ResultCode;
import com.guomei.service.SmsService;
import com.guomei.utils.HttpUtils;
import com.guomei.utils.RedisUtils;
import com.guomei.utils.Result;
import com.guomei.utils.SmsUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 短信服务实现类
 */
@Slf4j
@Service
public class SmsServiceImpl implements SmsService {
    @Resource
    SmsConfig smsBaoConfig;

    @Resource
    RedisUtils redisUtils;

    @Override
    public Result<Void> sendVerifyCode(SendVerifyCode sendVerifyCode) {
        // 参数校验
        if (!SmsUtils.isValidPhone(sendVerifyCode.getPhoneNumber())) {
            return Result.fail(ResultCode.PARAM_ERROR.getCode(), "手机号格式不正确");
        }
        // 检查是否已存在生效中的验证码
        String redisKey = RedisConstants.SMS_CODE_PREFIX + sendVerifyCode.getPhoneNumber();
        if (redisUtils.hasKey(redisKey)) {
            // 检查剩余过期时间
            Long expireTime = redisUtils.getExpire(redisKey);
            if (expireTime != null && expireTime > 0) {
                return Result.fail(ResultCode.PARAM_ERROR.getCode(),
                        "验证码已发送，请" + expireTime + "秒后再试");
            }
        }


        //随机生成六位验证码
        String code = String.valueOf((int) (Math.random() * 1000000));
        // 生成短信内容（替换模板占位符）
        String content = String.format(
                smsBaoConfig.getVerifyCodeTemplate(),
                smsBaoConfig.getSignName(),
                code
        );

        return sendSms(sendVerifyCode.getPhoneNumber(), content, code);
    }

    @Override
    public Result<Void> sendCustomSms(String phoneNumber, String content) {
        // 参数校验
        if (!SmsUtils.isValidPhone(phoneNumber)) {
            return Result.fail(ResultCode.PARAM_ERROR.getCode(), "手机号格式不正确");
        }
        if (content == null || content.trim().isEmpty()) {
            return Result.fail(ResultCode.PARAM_ERROR.getCode(), "短信内容不能为空");
        }
        if (!content.contains(smsBaoConfig.getSignName())) {
            log.warn("短信内容未包含签名，可能导致发送失败：{}", content);
        }
        //随机生成六位验证码
        String code = String.valueOf((int) (Math.random() * 1000000));

        return sendSms(phoneNumber, content, code);
    }


    /**
     * 发送短信核心方法
     */
    private Result<Void> sendSms(String phoneNumber, String content, String code) {
        try {
            // 构建请求参数
            StringBuffer httpArg = new StringBuffer();
            httpArg.append("u=").append(smsBaoConfig.getUsername()).append("&");
            httpArg.append("p=").append(md5(smsBaoConfig.getPassword())).append("&");
            httpArg.append("m=").append(phoneNumber).append("&");
            httpArg.append("c=").append(encodeUrlString(content, "UTF-8"));


            // 使用HttpUtils发送GET请求（短信宝API要求GET方式）
            String result = request(smsBaoConfig.getApiUrl(), httpArg.toString());
            log.info("短信发送响应: {}", result);

            // 解析响应结果（短信宝格式：0,消息ID 或 错误码,错误信息）
            return parseSendResult(result, phoneNumber, code);
        } catch (Exception e) {
            log.error("短信发送异常，手机号：{}", phoneNumber, e);
            return Result.error("短信发送异常：" + e.getMessage());
        }
    }

    /**
     * 解析短信发送响应结果
     */
    private Result<Void> parseSendResult(String result, String phoneNumber, String code) {
        if (result == null || result.isEmpty()) {
            return Result.error("短信发送失败，无响应");
        }
        if ("0".equals(result)) {
            // 发送成功
            log.info("短信发送成功，手机号：{}，消息内容：{}", phoneNumber, result);
            redisUtils.set(RedisConstants.SMS_CODE_PREFIX + phoneNumber, code, RedisConstants.SMS_CODE_EXPIRE_TIME);
            log.info("短信验证码已保存，手机号：{}，验证码：{}，redisKey：{}", phoneNumber, code, RedisConstants.SMS_CODE_PREFIX + phoneNumber);
            return Result.success();
        } else {
            // 发送失败
            log.error("短信发送失败，手机号：{}，错误信息：{}", phoneNumber, result);
            return Result.fail(ResultCode.SMS_ERROR.getCode(), "短信发送失败：");
        }
    }

    /**
     * 解析余额查询响应结果
     */
    private Result<Double> parseBalanceResult(String result) {
        if (result == null || result.isEmpty()) {
            return Result.error("查询余额失败，无响应");
        }
        String[] parts = result.split(",");
        if (parts.length < 2) {
            return Result.error("查询余额失败，响应格式错误：" + result);
        }
        if ("0".equals(parts[0])) {
            // 查询成功
            double balance = Double.parseDouble(parts[1]);
            return Result.success(balance);
        } else {
            // 查询失败
            return Result.fail(ResultCode.SMS_ERROR.getCode(), "查询余额失败：" + parts[1]);
        }
    }

    public static String request(String httpUrl, String httpArg) {
        BufferedReader reader = null;
        String result = null;
        StringBuffer sbf = new StringBuffer();
        httpUrl = httpUrl + "?" + httpArg;

        try {
            URL url = new URL(httpUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.connect();
            InputStream is = connection.getInputStream();
            reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            String strRead = reader.readLine();
            if (strRead != null) {
                sbf.append(strRead);
                while ((strRead = reader.readLine()) != null) {
                    sbf.append("\n");
                    sbf.append(strRead);
                }
            }
            reader.close();
            result = sbf.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static String md5(String plainText) {
        StringBuffer buf = null;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(plainText.getBytes());
            byte b[] = md.digest();
            int i;
            buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return buf.toString();
    }

    public static String encodeUrlString(String str, String charset) {
        String strret = null;
        if (str == null)
            return str;
        try {
            strret = java.net.URLEncoder.encode(str, charset);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return strret;
    }

}
